<template>
  <el-tree
    v-bind="$attrs"
    v-on="$listeners"
    ref="elTreeRef"
    :lazy="true"
    :load="loadFolders"
    node-key="ASSET_LABEL_SEQ"
    :props="{
      isLeaf: 'isLeaf',
      ...($attrs || {}).props
    }"
  >
    <template #default="{ node, data }">
      <slot :node="node" :data="data"></slot>
    </template>
  </el-tree>
</template>

<script>
import { getSubFolderTree } from "@/api/folder";
import { labelTypeTeam } from "@/constant";
import { threadLock } from "@/utils/lock";
import { uuid } from "@/utils";

// 缓存已加载的文件夹
const cacheFolders = new Map();

/**
 * 获取路径（从缓存里获取） TODO
 * @param folderId
 */
export const getPath = folderId => {};

/**
 * 文件夹树
 * 1、虽然是懒加载，但是数据的children依旧有效。
 * 2、但是重置 children，是增加数据，所以需要先清空 node.childNodes
 */
export default {
  name: "FolderTree",
  props: {
    folderType: {
      type: String,
      default: labelTypeTeam
    },
    propGetSubFolders: {
      type: Function
    },
    // 每次加载文件夹时你可以利用此回调过滤掉你不想展示的文件夹
    filterFolders: {
      type: Function
    }
  },
  data() {
    return {
      resolveMap: new Map(),
      foldersMap: new Map()
    };
  },
  methods: {
    /**
     * 1、在点击树节点下拉箭头时，获取下级文件夹的数据
     * @date 2023-12-06
     * @param {any} node
     * @param {any} resolve
     * @returns {any}
     */
    async loadFolders(node, resolve) {
      const unlock = await threadLock();
      try {
        // 1、将 resolve 存起来，给刷新用
        const folderId =
          node.data && node.data.ASSET_LABEL_SEQ
            ? node.data.ASSET_LABEL_SEQ
            : -1;
        this.resolveMap.set(folderId, resolve);

        //2、获取下级数据
        const children = await this.getNextData(folderId);
        if (children) {
          resolve(children);
        }
      } finally {
        unlock();
      }
    },
    /**
     * 根据文件夹标识获取文件夹的下级节点数据
     * 有缓存从缓存读取，没有就从接口获取
     * @date 2023-12-06
     * @param {any} parentId
     * @returns {any}
     */
    async getNextData(parentId) {
      /* 
        因为点击时，需要加载子节点。
        但是这个时候，el-tree 中还没有加载子节点，所以需要缓存起来，防止重复加载
      */
      if (this.foldersMap.has(parentId)) {
        const parentFolder = this.foldersMap.get(parentId);
        if (parentFolder.isLoad) {
          //console.log("从缓存中获取");
          this.$emit("loadFolder", parentFolder, parentFolder.children);
          return parentFolder.children;
        }
        //console.log("缓存中不存在", parentId);
      }
      try {
        const children = await this.loadSubFoldersByFolderId(parentId);
        return children;
      } catch (e) {
        //console.log(e);
      }
    },
    /** 在点击时，需要在目录树外查看子节点 */
    async getSubFoldersData(folderId) {
      const unlock = await threadLock();
      try {
        /* 
        因为点击时，需要加载子节点。
        但是这个时候，el-tree 中还没有加载子节点，所以需要缓存起来，防止重复加载
      */
        if (this.foldersMap.has(folderId)) {
          const parentFolder = this.foldersMap.get(folderId);
          if (parentFolder.isLoad) {
            return parentFolder.children;
          }
        } else {
          // 全部
          if (folderId === -1) {
            this.foldersMap.set(folderId, {
              ASSET_LABEL_SEQ: -1,
              unikey: uuid(),
              children: [],
              isRoot: true,
              isLoad: false
            });
          }
        }
        return await this.loadSubFoldersByFolderId(folderId);
      } finally {
        unlock();
      }
    },
    async getSubFoldersAsync(folderId, parentNode) {
      if (this.propGetSubFolders) {
        return this.propGetSubFolders(folderId, parentNode);
      }
      const { _success, _data } = await getSubFolderTree({
        folderId,
        folderType: this.folderType
      });
      let dealData = this.dealShortFolder(_data, parentNode)
      if (!_success) throw "加载子目录树失败";
      return dealData;
    },
    /** 加载子文件夹 */
    async loadSubFoldersByFolderId(folderId) {
      //console.log("loadSubFoldersByFolderId", folderId);
      // 全部
      if (folderId === -1 && !this.foldersMap.has(-1)) {
        //console.log("插入全部文件夹");
        this.foldersMap.set(-1, {
          unikey: uuid(),
          ASSET_LABEL_SEQ: -1,
          children: [],
          isRoot: true,
          isLoad: false
        });
      }
      const parentFolder = this.foldersMap.get(folderId);
      const folders = await this.getSubFoldersAsync(folderId, parentFolder);
      // folders
      folders.forEach(subFolder => {
        if (subFolder.LABEL_NAME === "广告投放效果监测") {
          subFolder.nodeType = "advert";
        } else if (parentFolder.nodeType) {
          subFolder.nodeType = parentFolder.nodeType;
        }
        subFolder.isLeaf = !subFolder.hasNext;
        subFolder.isLoad = false;
        subFolder.children = [];
        // 保留下级数据，避免查询。如果要连下级数据一起清楚，需要在上层调用时，清理 this.foldersMap中的数据
        if (this.foldersMap.has(subFolder.ASSET_LABEL_SEQ)) {
          const oldSubFolder = this.foldersMap.get(subFolder.ASSET_LABEL_SEQ);
          subFolder.children = oldSubFolder.children;
          subFolder.isLoad = oldSubFolder.isLoad;
        }
        subFolder.unikey = uuid();
        //建立新的下级缓存
        this.foldersMap.set(subFolder.ASSET_LABEL_SEQ, subFolder);
      });
      // 更新缓存
      cacheFolders.set(folderId, folders);
      parentFolder.isLoad = true;
      // todo 直接改children 好像不能刷新，待验证
      // parentFolder.children.clear();
      parentFolder.children.splice(0, parentFolder.children.length, ...folders);
      // 外部过滤文件夹
      if (this.filterFolders) {
        //console.log("this.filterFolders");
        parentFolder.children = this.filterFolders(parentFolder.children);
      }

      this.$emit("loadFolder", parentFolder, parentFolder.children);

      return parentFolder.children; // 不能返回 folders。会导致和缓存内不是一个对象
    },
    /**
     * 刷新根文件夹
     */
    async refreshRootFolders(clearSubFolders) {
      if (!this.resolveMap.has(-1)) {
        return;
      }
      //1、 清除子树记录
      let folderInfo = this.foldersMap.get(-1);
      if (folderInfo && clearSubFolders) {
        this.clearSubfoldersData(folderInfo.children);
      }
      const resolve = this.resolveMap.get(-1);
      this.$refs.elTreeRef.root.childNodes = [];
      const children = await this.loadSubFoldersByFolderId(-1);
      this.$refs.elTreeRef.root.childNodes = [];
      resolve(children);
    },
    /**
     * 是否清理子树
     * @date 2023-12-06
     * @param {any} folderId
     * @param {any} clearSubFolders 是否清理子树
     * @returns {any}
     */
    async refreshSubFolders(folderId, clearSubFolders = true) {
      const unlock = await threadLock();
      try {
        //console.log("refreshSubFolders", folderId);
        if (!folderId || folderId === -1) {
          this.refreshRootFolders(clearSubFolders);
          return;
        }
        //1、 清除子树记录
        let folderInfo = this.foldersMap.get(folderId);
        if (folderInfo && clearSubFolders) {
          this.clearSubfoldersData(folderInfo.children);
        }
        const node = this.$refs.elTreeRef.getNode(folderId);
        if (!node) {
          return;
        }
        node.childNodes = [];
        const children = await this.loadSubFoldersByFolderId(folderId);
        let isRreshParent = false;
        // 因为叶子节点点加了元素后，不出现小箭头，只能通过 expand 展开
        if (node.isLeaf && children.length > 0) {
          node.isLeaf = true;
          node.data.isLeaf = true;
          // node.expand();
          isRreshParent = true;
        }
        //如果子树为空，叶子节点更新
        if (children.length === 0 && !node.isLeaf) {
          node.isLeaf = false;
          node.data.isLeaf = false;
          isRreshParent = true;
        }

        // 因为 isLeaf 更新后无效，通过设置父级来重置
        if (isRreshParent) {
          //console.log("refreshSubFolders isRreshParent");
          const parentNode = node.parent;
          if (
            !parentNode ||
            !parentNode.data ||
            !parentNode.data.ASSET_LABEL_SEQ
          ) {
            this.refreshRootFolders();
            return;
          }
          const resolve = this.resolveMap.get(parentNode.data.ASSET_LABEL_SEQ);
          const parentChildren = await this.loadSubFoldersByFolderId(
            parentNode.data.ASSET_LABEL_SEQ
          );
          parentNode.childNodes = [];
          // resolve([]); // 必须先调用一次，清空内部的变量，直接调用可能存在重复的键
          resolve(parentChildren);
        }
      } finally {
        unlock();
      }
    },
    /**
     * 清理子文件夹的数据
     */
    clearSubfoldersData(children) {
      //console.log("清理子文件夹的数据", children);
      children.forEach(childInfo => {
        this.foldersMap.delete(childInfo.ASSET_LABEL_SEQ);
        this.clearSubfoldersData(childInfo.children);
      });
    },
    append(folderId, data) {
      //console.log("append", folderId, data);
      data.isLeaf = true;
      data.isLoad = false;
      data.children = [];
      data.unikey = uuid();
      this.foldersMap.set(data.ASSET_LABEL_SEQ, data);

      if (folderId === -1) {
        const rootFolder = this.foldersMap.get(folderId);
        /*  1、根节点因为没有父节点
         *  2、根节点没有data属性，所以只能使用缓存数据取
         */
        if (rootFolder && rootFolder.isLoad) {
          this.refreshRootFolders();
          return;
        }
      } else {
        this.$refs.elTreeRef.append(data, folderId);
        //添加对兄弟节点没影响，所以不需要清空父节点的子节点。
        // this.refreshSubFolders(folderId, false);
      }
    },
    removeNode(deleteFolderInfo) {
      const { ASSET_LABEL_SEQ, PNT_LABEL_ID } = deleteFolderInfo;
      const node = this.$refs.elTreeRef.getNode(ASSET_LABEL_SEQ);
      //1、 清除子树记录
      let folderInfo = this.foldersMap.get(ASSET_LABEL_SEQ);
      if (folderInfo) {
        this.clearSubfoldersData(folderInfo.children);
        this.foldersMap.delete(ASSET_LABEL_SEQ);
      }
      if (!node || PNT_LABEL_ID === -1) {
        //删除对兄弟节点没影响，所以不需要清空父节点的子节点。
        this.refreshSubFolders(PNT_LABEL_ID, false);
        return;
      }
      this.$refs.elTreeRef.remove(node);
    },
    updateNodeData({ ASSET_LABEL_SEQ, ...newFolder }) {
      const node = this.$refs.elTreeRef.getNode(ASSET_LABEL_SEQ);
      if (!node) {
        return;
      }
      const curNodeData = node.data;
      if (!curNodeData) {
        console.warn("修改团队文件夹的节点时没有从树中找到节点");
        return;
      }
      Object.entries(newFolder).forEach(([key, value]) => {
        this.$set(curNodeData, key, value);
      });
    },
    /**
     * 获取文件夹的路径
     * @param {number} ASSET_LABEL_SEQ 文件夹的ID
     */
    getNodeData(ASSET_LABEL_SEQ) {
      let node = this.$refs.elTreeRef.getNode(ASSET_LABEL_SEQ);
      if (!node || !node.data) {
        return null;
      }
      return node.data;
    },
    /**
     * 获取文件夹的路径
     * @param {number} ASSET_LABEL_SEQ 文件夹的ID
     */
    getFolderPathList(ASSET_LABEL_SEQ) {
      let node = this.$refs.elTreeRef.getNode(ASSET_LABEL_SEQ);
      if (!node) {
        return [];
      }
      const path = [];
      do {
        path.unshift(node.data);
        node = node.parent;
      } while (node && node.data && node.data.ASSET_LABEL_SEQ);
      return path;
    },
    /**
     * 兼容快捷方式，前端自定义处理快捷方式已经
     */
     dealShortFolder(children, pNode){
      children.forEach((item) => {
        if(pNode && (pNode.linkType == 1 || pNode.linkResource)){
          item.linkResource = true
          if(item.linkType == 1){
            // 证明当前子文件夹也是 快捷方式
            item.topLinkId = item.ASSET_LABEL_SEQ
          }else if(pNode && pNode.topLinkId ){
            item.topLinkId = pNode.topLinkId
          }

          let assetSeq = item.ASSET_LABEL_SEQ
            if(pNode.fullPath){
              item.fullPath = pNode.fullPath + '-|-'+ item.ASSET_LABEL_SEQ
            }else{
              item.fullPath = pNode.ASSET_LABEL_SEQ + '-|-'+ item.ASSET_LABEL_SEQ
            }
            item.PNT_LABEL_ID = pNode.ASSET_LABEL_SEQ

            item.ASSET_LABEL_SEQ = item.fullPath
            item.reallId = assetSeq

        }else{
          item.linkResource = false

        }

      })
      return children
    },
  },
  mounted() {
    // el-tree 中的 root，没有 data 值。导致自带的拖拽功能报错。
    this.$refs.elTreeRef.root.data = [];
  }
};
</script>